home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 May / may_2001.iso / intercd / root / Multimedia / ^DivX_Article / virtualdub / VirtualDub-source-1_4d / about.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-20  |  15.4 KB  |  628 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Copyright (C) 1998-2001 Avery Lee
  3. //
  4. //    This program is free software; you can redistribute it and/or modify
  5. //    it under the terms of the GNU General Public License as published by
  6. //    the Free Software Foundation; either version 2 of the License, or
  7. //    (at your option) any later version.
  8. //
  9. //    This program is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //    GNU General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU General Public License
  15. //    along with this program; if not, write to the Free Software
  16. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <math.h>
  19. #include <windows.h>
  20. #include <vfw.h>
  21.  
  22. #include "resource.h"
  23. #include "vbitmap.h"
  24. #include "auxdlg.h"
  25. #include "oshelper.h"
  26.  
  27. #include "IAmpDecoder.h"
  28.  
  29. extern "C" unsigned long version_num;
  30. extern "C" char version_time[];
  31.  
  32. extern HINSTANCE g_hInst;
  33.  
  34. ///////////////////////////////////////////////////////////////////////////
  35.  
  36. static HDC g_hdcAboutDisplay;
  37. static HBITMAP g_hbmAboutDisplay;
  38. static HGDIOBJ g_hgoAboutDisplay;
  39. static BITMAPINFOHEADER g_bihAboutDisplay;
  40. static void *g_pvAboutDisplay;
  41. static void *g_pvAboutDisplayBack;
  42. static VBitmap g_vbAboutSrc, g_vbAboutDst;
  43.  
  44. ///////////////////////////////////////////////////////////////////////////
  45.  
  46. struct TriPt {
  47.     double x, y;
  48.     double u, v;
  49. };
  50.  
  51. typedef unsigned short Pixel16;
  52.  
  53. // Triangle setup based on Chris Hecker's GDM article on texture mapping.
  54. // We define pixel centers on the display to be at integers.
  55.  
  56. void RenderTriangle(Pixel16 *dst, long dstpitch, Pixel16 *tex, TriPt *pt1, TriPt *pt2, TriPt *pt3) {
  57.     TriPt *pt, *pl, *pr;
  58.  
  59.     // Find top point
  60.  
  61.     if (pt1->y < pt2->y)        // 1 < 2
  62.         if (pt1->y < pt3->y) {    // 1 < 2,3
  63.             pt = pt1;
  64.             pr = pt2;
  65.             pl = pt3;
  66.         } else {                // 3 < 1 < 2
  67.             pt = pt3;
  68.             pr = pt1;
  69.             pl = pt2;
  70.         }
  71.     else                        // 2 < 1
  72.         if (pt2->y < pt3->y) {    // 2 < 1,3
  73.             pt = pt2;
  74.             pr = pt3;
  75.             pl = pt1;
  76.         } else {                // 3 < 2 < 1
  77.             pt = pt3;
  78.             pr = pt1;
  79.             pl = pt2;
  80.         }
  81.  
  82.     if (pl->y == pt->y && pt->y == pr->y)
  83.         return;
  84.  
  85.     // Compute gradients
  86.  
  87.     double A;
  88.     double one_over_A;
  89.     double dudx, dvdx;
  90.     double dudy, dvdy;
  91.     int dudxi, dvdxi;
  92.  
  93.     A = (pt->y - pl->y) * (pr->x - pl->x) - (pt->x - pl->x) * (pr->y - pl->y);
  94.     one_over_A = 1.0 / A;
  95.     dudx = ((pr->u - pl->u) * (pt->y - pl->y) - (pt->u - pl->u) * (pr->y - pl->y)) * one_over_A;
  96.     dvdx = ((pr->v - pl->v) * (pt->y - pl->y) - (pt->v - pl->v) * (pr->y - pl->y)) * one_over_A;
  97.     dudy = ((pr->u - pl->u) * (pt->x - pl->x) - (pt->u - pl->u) * (pr->x - pl->x)) * -one_over_A;
  98.     dvdy = ((pr->v - pl->v) * (pt->x - pl->x) - (pt->v - pl->v) * (pr->x - pl->x)) * -one_over_A;
  99.  
  100.     dudxi = (long)(dudx * 16777216.0);
  101.     dvdxi = (long)(dvdx * 16777216.0);
  102.     
  103.     // Compute edge walking parameters
  104.  
  105.     double dxl1=0, dxr1=0, dul1=0, dvl1=0;
  106.     double dxl2=0, dxr2=0, dul2=0, dvl2=0;
  107.  
  108.     // Compute left-edge interpolation parameters for first half.
  109.  
  110.     if (pl->y != pt->y) {
  111.         dxl1 = (pl->x - pt->x) / (pl->y - pt->y);
  112.  
  113.         dul1 = dudy + dxl1 * dudx;
  114.         dvl1 = dvdy + dxl1 * dvdx;
  115.     }
  116.  
  117.     // Compute right-edge interpolation parameters for first half.
  118.  
  119.     if (pr->y != pt->y) {
  120.         dxr1 = (pr->x - pt->x) / (pr->y - pt->y);
  121.     }
  122.  
  123.     // Reject backfaces.
  124.  
  125.     if (dxl1 >= dxr1)
  126.         return;
  127.  
  128.     // Compute third-edge interpolation parameters.
  129.  
  130.     if (pr->y != pl->y) {
  131.         dxl2 = (pr->x - pl->x) / (pr->y - pl->y);
  132.  
  133.         dul2 = dudy + dxl2 * dudx;
  134.         dvl2 = dvdy + dxl2 * dvdx;
  135.  
  136.         dxr2 = dxl2;
  137.     }
  138.  
  139.     // Initialize parameters for first half.
  140.     //
  141.     // We place pixel centers at (x+0.5, y+0.5).
  142.  
  143.     double xl, xr, ul, vl, yf;
  144.     int y, y1, y2;
  145.  
  146.     // y_start < y+0.5 to include pixel y.
  147.  
  148.     y = floor(pt->y + 0.5);
  149.     yf = (y+0.5) - pt->y;
  150.  
  151.     xl = pt->x + dxl1 * yf;
  152.     xr = pt->x + dxr1 * yf;
  153.     ul = pt->u + dul1 * yf;
  154.     vl = pt->v + dvl1 * yf;
  155.  
  156.     // Initialize parameters for second half.
  157.  
  158.     double xl2, xr2, ul2, vl2;
  159.  
  160.     if (pl->y > pr->y) {        // Left edge is long side
  161.         dxl2 = dxl1;
  162.         dul2 = dul1;
  163.         dvl2 = dvl1;
  164.  
  165.         y1 = floor(pr->y + 0.5);
  166.         y2 = floor(pl->y + 0.5);
  167.  
  168.         yf = (y1+0.5) - pr->y;
  169.  
  170.         // Step left edge.
  171.  
  172.         xl2 = xl + dxl1 * (y1 - y);
  173.         ul2 = ul + dul1 * (y1 - y);
  174.         vl2 = vl + dvl1 * (y1 - y);
  175.  
  176.         // Prestep right edge.
  177.  
  178.         xr2 = pr->x + dxr2 * yf;
  179.     } else {                    // Right edge is long side
  180.         dxr2 = dxr1;
  181.  
  182.         y1 = floor(pl->y + 0.5);
  183.         y2 = floor(pr->y + 0.5);
  184.  
  185.         yf = (y1+0.5) - pl->y;
  186.  
  187.         // Prestep left edge.
  188.  
  189.         xl2 = pl->x + dxl2 * yf;
  190.         ul2 = pl->u + dul2 * yf;
  191.         vl2 = pl->v + dvl2 * yf;
  192.  
  193.         // Step right edge.
  194.  
  195.         xr2 = xr + dxr1 * (y1 - y);
  196.     }
  197.  
  198.     // Rasterize!
  199.  
  200.     int u_correct=0, v_correct=0;
  201.  
  202.     if (dudx < 0)            u_correct = -1;
  203.     else if (dudx > 0)        u_correct = 0;
  204.     else if (dul1 < 0)        u_correct = -1;
  205.  
  206.     if (dvdx < 0)            v_correct = -1;
  207.     else if (dvdx > 0)        v_correct = 0;
  208.     else if (dvl1 < 0)        v_correct = -1;
  209.  
  210. /*    if (y < 0)
  211.         y = 0;
  212.  
  213.     if (y2 > 160)
  214.         y2 = 160;*/
  215.  
  216.     dst += dstpitch * y;
  217.  
  218.     while(y < y2) {
  219.         if (y == y1) {
  220.             xl = xl2;
  221.             xr = xr2;
  222.             ul = ul2;
  223.             vl = vl2;
  224.             dxl1 = dxl2;
  225.             dxr1 = dxr2;
  226.             dul1 = dul2;
  227.             dvl1 = dvl2;
  228.         }
  229.  
  230.         int x1, x2;
  231.         double xf;
  232.         int u, v;
  233.  
  234.         // x_left must be less than (x+0.5) to include pixel x.
  235.  
  236.         x1        = (int)floor(xl + 0.5);
  237.         x2        = (int)floor(xr + 0.5);
  238.         xf        = (x1+0.5) - xl;
  239.         
  240.         u        = ((int)((ul + xf * dudx)*16777216.0) /*>> mipmaplevel*/) + u_correct;
  241.         v        = ((int)((vl + xf * dvdx)*16777216.0) /*>> mipmaplevel*/) + v_correct;
  242.  
  243. /*        if (x1<0) {
  244.             x1=0;
  245.             u -= dudxi * x1;
  246.             v -= dvdxi * x1;
  247.         }
  248.         if (x2>160) x2=160;*/
  249.  
  250.         while(x1 < x2) {
  251. //            dst[x1++] = tex[(u>>24) + (v>>24)*64];
  252.             int A = tex[(u>>24) + (v>>24)*32];
  253.             int B = dst[x1];
  254.  
  255.             dst[x1] = ((A&0x7bde)>>1) + ((B>>1)&0x3def) + (A&B&0x0421);
  256.             ++x1;
  257.  
  258.             u += dudxi;
  259.             v += dvdxi;
  260.         }
  261.  
  262.         dst += dstpitch;
  263.         xl += dxl1;
  264.         xr += dxr1;
  265.         ul += dul1;
  266.         vl += dvl1;
  267.  
  268.         ++y;
  269.     }
  270. }
  271.  
  272. ///////////////////////////////////////////////////////////////////////////
  273.  
  274. #pragma optimize("t", off)
  275. #pragma optimize("s", on)
  276.  
  277. static BOOL CALLBACK HideAllButOKCANCELProc(HWND hwnd, LPARAM lParam) {
  278.     UINT id = GetWindowLong(hwnd, GWL_ID);
  279.  
  280.     if (id != IDOK && id != IDCANCEL)
  281.         ShowWindow(hwnd, SW_HIDE);
  282.  
  283.     return TRUE;
  284. }
  285.  
  286. static void CALLBACK AboutTimerProc(UINT uID, UINT, DWORD dwUser, DWORD, DWORD) {
  287.     PostMessage((HWND)dwUser, WM_APP+0, 0, 0);
  288. }
  289.  
  290. BOOL APIENTRY AboutDlgProc( HWND hDlg, UINT message, UINT wParam, LONG lParam)
  291. {
  292.     static bool bTimerSet;
  293.     static bool bRender;
  294.     static MMRESULT mmTimer;
  295.     static Pixel16 *tex;
  296.     static RECT rBounce;
  297.     static RECT rDirtyLast;
  298.     static int xpos, ypos, xvel, yvel;
  299.     static double vx[8][3];
  300.     static const int faces[6][4] = {
  301.         { 0, 1, 4, 5 },
  302.         { 2, 6, 3, 7 },
  303.         { 0, 4, 2, 6 },
  304.         { 1, 3, 5, 7 },
  305.         { 0, 2, 1, 3 },
  306.         { 4, 5, 6, 7 },
  307.     };
  308.  
  309.     switch (message)
  310.     {
  311.         case WM_INITDIALOG:
  312.             {
  313.                 char buf[128];
  314.  
  315.                 wsprintf(buf, "Build %d/"
  316. #ifdef _DEBUG
  317.                     "debug"
  318. #else
  319.                     "release"
  320. #endif
  321.                     " (%s)", version_num, version_time);
  322.  
  323.                 SetDlgItemText(hDlg, IDC_FINALS_SUCK, buf);
  324.  
  325.                 HRSRC hrsrc;
  326.  
  327.                 if (hrsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_CREDITS), "STUFF")) {
  328.                     HGLOBAL hGlobal;
  329.                     if (hGlobal = LoadResource(NULL, hrsrc)) {
  330.                         const char *pData, *pLimit;
  331.  
  332.                         if (pData = (const char *)LockResource(hGlobal)) {
  333.                             HWND hwndItem = GetDlgItem(hDlg, IDC_CREDITS);
  334.                             const INT tab = 80;
  335.  
  336.                             pLimit = pData + SizeofResource(NULL, hrsrc);
  337.  
  338.                             SendMessage(hwndItem, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
  339.                             SendMessage(hwndItem, LB_SETTABSTOPS, 1, (LPARAM)&tab);
  340.  
  341.                             while(pData < pLimit) {
  342.                                 char *t = buf;
  343.  
  344.                                 while(pData < pLimit && *pData!='\r' && *pData!='\n')
  345.                                     *t++ = *pData++;
  346.  
  347.                                 while(pData < pLimit && (*pData=='\r' || *pData=='\n'))
  348.                                     ++pData;
  349.  
  350.                                 *t = 0;
  351.  
  352.                                 if (t > buf)
  353.                                     SendMessage(GetDlgItem(hDlg, IDC_CREDITS), LB_ADDSTRING, 0, (LPARAM)buf);
  354.                             }
  355.  
  356.                             FreeResource(hGlobal);
  357.                         }
  358.                         FreeResource(hGlobal);
  359.                     }
  360.                 }
  361.  
  362.                 IAMPDecoder *iad = CreateAMPDecoder();
  363.  
  364.                 if (iad) {
  365.                     wsprintf(buf, "MPEG audio decoder: %s", iad->GetAmpVersionString());
  366.                     delete iad;
  367.                     SetDlgItemText(hDlg, IDC_MP3_DECODER, buf);
  368.                 }
  369.  
  370.                 // Showtime!  Invalidate the entire window, force an update, and show the window.
  371.  
  372.                 ShowWindow(hDlg, SW_SHOW);
  373.                 InvalidateRect(hDlg, NULL, TRUE);
  374.                 UpdateWindow(hDlg);
  375.  
  376.                 // Grab the client area.
  377.  
  378.                 HDC hdc;
  379.                 RECT r;
  380.  
  381.                 GetClientRect(hDlg, &r);
  382.  
  383.                 g_bihAboutDisplay.biSize            = sizeof(BITMAPINFOHEADER);
  384.                 g_bihAboutDisplay.biWidth            = r.right;
  385.                 g_bihAboutDisplay.biHeight            = r.bottom;
  386.                 g_bihAboutDisplay.biBitCount        = 16;
  387.                 g_bihAboutDisplay.biPlanes            = 1;
  388.                 g_bihAboutDisplay.biCompression        = BI_RGB;
  389.                 g_bihAboutDisplay.biXPelsPerMeter    = 80;
  390.                 g_bihAboutDisplay.biYPelsPerMeter    = 80;
  391.                 g_bihAboutDisplay.biClrUsed            = 0;
  392.                 g_bihAboutDisplay.biClrImportant    = 0;
  393.  
  394.                 if (hdc = GetDC(hDlg)) {
  395.                     if (g_hdcAboutDisplay = CreateCompatibleDC(hdc)) {
  396.                         if (g_hbmAboutDisplay = CreateDIBSection(g_hdcAboutDisplay, (const BITMAPINFO *)&g_bihAboutDisplay, DIB_RGB_COLORS, &g_pvAboutDisplay, NULL, 0)) {
  397.                             g_hgoAboutDisplay = SelectObject(g_hdcAboutDisplay, g_hbmAboutDisplay);
  398.  
  399.                             BitBlt(g_hdcAboutDisplay, 0, 0, r.right, r.bottom, hdc, 0, 0, SRCCOPY);
  400.                             GdiFlush();
  401.  
  402.                             if (tex = new Pixel16[32*32]) {
  403.                                 g_pvAboutDisplayBack = malloc(((r.right+3)&~3)*2*r.bottom);
  404.  
  405.                                 if (g_pvAboutDisplayBack) {
  406.                                     g_vbAboutSrc.init(g_pvAboutDisplayBack, r.right, r.bottom, 16);
  407.                                     g_vbAboutDst.init(g_pvAboutDisplay, &g_bihAboutDisplay);
  408.                                     g_vbAboutSrc.BitBlt(0, 0, &g_vbAboutDst, 0, 0, -1, -1);
  409.  
  410.                                     // Hide all controls.
  411.  
  412.                                     EnumChildWindows(hDlg, HideAllButOKCANCELProc, 0);
  413.  
  414.                                     // Grab the VirtualDub icon.
  415.  
  416.                                     HICON hico = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_VIRTUALDUB));
  417.  
  418.                                     DrawIcon(g_hdcAboutDisplay, 0, 0, hico);
  419.  
  420.                                     GdiFlush();
  421.  
  422.                                     VBitmap(tex, 32, 32, 16).BitBlt(0, 0, &g_vbAboutDst, 0, 0, 32, 32);
  423.  
  424.                                     g_vbAboutDst.BitBlt(0, 0, &g_vbAboutSrc, 0, 0, 32, 32);
  425.  
  426.                                     // Initialize cube vertices.
  427.  
  428.                                     {
  429.                                         int i,j;
  430.                                         double rs;
  431.  
  432.                                         if (r.right > r.bottom)
  433.                                             rs = r.bottom / (3.6*3.0);
  434.                                         else
  435.                                             rs = r.right / (3.6*3.0);
  436.  
  437.                                         for(i=0; i<8; i++) {
  438.                                             vx[i][0] = i&1 ? -rs : +rs;
  439.                                             vx[i][1] = i&2 ? -rs : +rs;
  440.                                             vx[i][2] = i&4 ? -rs : +rs;
  441.                                         }
  442.  
  443.                                         rBounce.left = rBounce.top = (int)ceil(rs*1.8);
  444.                                         rBounce.right = r.right - rBounce.left;
  445.                                         rBounce.bottom = r.bottom - rBounce.top;
  446.  
  447.                                         xpos = rand()%(rBounce.right-rBounce.left) + rBounce.left;
  448.                                         ypos = rand()%(rBounce.bottom-rBounce.top) + rBounce.top;
  449.                                         xvel = (rand()&2)-1;
  450.                                         yvel = (rand()&2)-1;
  451.  
  452.                                         rDirtyLast.top = rDirtyLast.left = 0;
  453.                                         rDirtyLast.right = rDirtyLast.bottom = 0;
  454.                                     }
  455.  
  456.                                     InvalidateRect(hDlg, NULL, TRUE);
  457.  
  458.                                     if (TIMERR_NOERROR == timeBeginPeriod(10)) {
  459.                                         bTimerSet = true;
  460.                                         bRender = true;
  461.  
  462.                                         mmTimer = timeSetEvent(10, 10, AboutTimerProc, (DWORD)hDlg, TIME_PERIODIC|TIME_CALLBACK_FUNCTION);
  463.                                     }
  464.                                 }
  465.                             }
  466.                         }
  467.                     }
  468.                 }
  469.  
  470.             }
  471.             return (TRUE);
  472.  
  473.         case WM_COMMAND:                      
  474.             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
  475.             {
  476.                 if (tex) {
  477.                     free(tex);
  478.                     tex = 0;
  479.                 }
  480.  
  481.                 if (g_pvAboutDisplayBack) {
  482.                     free(g_pvAboutDisplayBack);
  483.                     g_pvAboutDisplayBack = 0;
  484.                 }
  485.  
  486.                 if (g_hbmAboutDisplay) {
  487.                     DeleteObject(SelectObject(g_hdcAboutDisplay, g_hgoAboutDisplay));
  488.                     g_hbmAboutDisplay = NULL;
  489.                 }
  490.  
  491.                 if (g_hdcAboutDisplay) {
  492.                     DeleteDC(g_hdcAboutDisplay);
  493.                     g_hdcAboutDisplay = NULL;
  494.                 }
  495.  
  496.                 if (mmTimer)
  497.                     timeKillEvent(mmTimer);
  498.  
  499.                 if (bTimerSet)
  500.                     timeEndPeriod(33);
  501.  
  502.                 EndDialog(hDlg, TRUE);  
  503.                 return TRUE;
  504.             }
  505.             break;
  506.  
  507.         case WM_ERASEBKGND:
  508.             if (g_pvAboutDisplayBack) {
  509.                 SetWindowLong(hDlg, DWL_MSGRESULT, 0);
  510.                 return TRUE;
  511.             } else
  512.                 return FALSE;
  513.  
  514.         case WM_PAINT:
  515.             if (g_pvAboutDisplayBack) {
  516.                 HDC hdc;
  517.                 PAINTSTRUCT ps;
  518.  
  519.                 if (hdc = BeginPaint(hDlg, &ps)) {
  520.                     BitBlt(hdc, 0, 0, g_vbAboutDst.w, g_vbAboutDst.h,
  521.                         g_hdcAboutDisplay, 0, 0, SRCCOPY);
  522.  
  523.                     bRender = true;
  524.  
  525.                     EndPaint(hDlg, &ps);
  526.                 }
  527.                 return TRUE;
  528.             }
  529.             return FALSE;
  530.  
  531.         case WM_APP:
  532.             if (g_pvAboutDisplayBack && bRender) {
  533.                 HDC hdc;
  534.                 PAINTSTRUCT ps;
  535.  
  536.                 static double theta = 0.0;
  537.                 double xt, yt, zt;
  538.  
  539.                 bRender = false;
  540.  
  541.                 xt = sin(theta) / 80.0;
  542.                 yt = sin(theta + 3.1415926535 * 2.0 / 3.0) / 80.0;
  543.                 zt = sin(theta + 3.1415926535 * 4.0 / 3.0) / 80.0;
  544.                 theta = theta + 0.005;
  545.  
  546.                 xpos += xvel;
  547.                 ypos += yvel;
  548.  
  549.                 if (xpos<rBounce.left) { xpos = rBounce.left; xvel = +1; }
  550.                 if (xpos>rBounce.right) { xpos = rBounce.right; xvel = -1; }
  551.                 if (ypos<rBounce.top) { ypos = rBounce.top; yvel = +1; }
  552.                 if (ypos>rBounce.bottom) { ypos = rBounce.bottom; yvel = -1; }
  553.  
  554.                 RECT rDirty = { 0x7fffffff, 0x7fffffff, -1, -1 };
  555.                 RECT rDirty2;
  556.  
  557.                 for(int i=0; i<8; i++) {
  558.                     double x0 = vx[i][0];
  559.                     double y0 = vx[i][1];
  560.                     double z0 = vx[i][2];
  561.  
  562.                     double x1 = x0 * cos(zt) - y0 * sin(zt);
  563.                     double y1 = x0 * sin(zt) + y0 * cos(zt);
  564.                     double z1 = z0;
  565.  
  566.                     double x2 = x1 * cos(yt) - z1 * sin(yt);
  567.                     double y2 = y1;
  568.                     double z2 = x1 * sin(yt) + z1 * cos(yt);
  569.  
  570.                     double x3 = x2;
  571.                     double y3 = y2 * cos(xt) - z2 * sin(xt);
  572.                     double z3 = y2 * sin(xt) + z2 * cos(xt);
  573.  
  574.                     vx[i][0] = x3;
  575.                     vx[i][1] = y3;
  576.                     vx[i][2] = z3;
  577.  
  578.                     int ix1 = (int)floor(x3);
  579.                     int ix2 = (int)ceil(x3);
  580.                     int iy1 = (int)floor(y3);
  581.                     int iy2 = (int)ceil(y3);
  582.  
  583.                     if (rDirty.left   > ix1) rDirty.left   = ix1;
  584.                     if (rDirty.right  < ix1) rDirty.right  = ix1;
  585.                     if (rDirty.top    > iy1) rDirty.top    = iy1;
  586.                     if (rDirty.bottom < iy1) rDirty.bottom = iy1;
  587.                 }
  588.  
  589.                 OffsetRect(&rDirty, xpos, ypos);
  590.                 UnionRect(&rDirty2, &rDirty, &rDirtyLast);
  591.                 rDirtyLast = rDirty;
  592.  
  593.                 ++rDirty2.right;
  594.                 ++rDirty2.bottom;
  595.  
  596.                 GdiFlush();
  597.  
  598.                 g_vbAboutDst.BitBlt(rDirty2.left, rDirty2.top, &g_vbAboutSrc, rDirty2.left, rDirty2.top,
  599.                     rDirty2.right+1-rDirty2.left, rDirty2.bottom+1-rDirty2.top);
  600.  
  601.                 TriPt v[4];
  602.  
  603.                 v[0].u =  0;    v[0].v = 0;
  604.                 v[1].u = 32;    v[1].v = 0;
  605.                 v[2].u =  0;    v[2].v = 32;
  606.                 v[3].u = 32;    v[3].v = 32;
  607.  
  608.                 for(int f=0; f<6; f++) {
  609.                     v[0].x = vx[faces[f][0]][0] + xpos;
  610.                     v[0].y = vx[faces[f][0]][1] + ypos;
  611.                     v[1].x = vx[faces[f][1]][0] + xpos;
  612.                     v[1].y = vx[faces[f][1]][1] + ypos;
  613.                     v[2].x = vx[faces[f][2]][0] + xpos;
  614.                     v[2].y = vx[faces[f][2]][1] + ypos;
  615.                     v[3].x = vx[faces[f][3]][0] + xpos;
  616.                     v[3].y = vx[faces[f][3]][1] + ypos;
  617.  
  618.                     RenderTriangle((Pixel16 *)g_vbAboutDst.Address32(0,0), -g_vbAboutDst.pitch/2, tex, v+0, v+1, v+2);
  619.                     RenderTriangle((Pixel16 *)g_vbAboutDst.Address32(0,0), -g_vbAboutDst.pitch/2, tex, v+2, v+1, v+3);
  620.                 }
  621.  
  622.                 InvalidateRect(hDlg, &rDirty2, FALSE);
  623.             }
  624.             return TRUE;
  625.     }
  626.     return FALSE;
  627. }
  628.